package com.sheng.leetcode.year2023.month05.day26;

import lombok.var;
import org.junit.Test;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * @author liusheng
 * @date 2023/05/26
 * <p>
 * 1091. 二进制矩阵中的最短路径<p>
 * <p>
 * 给你一个 n x n 的二进制矩阵 grid 中，返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径，返回 -1 。<p>
 * 二进制矩阵中的 畅通路径 是一条从 左上角 单元格（即，(0, 0)）到 右下角 单元格（即，(n - 1, n - 1)）的路径，该路径同时满足下述要求：<p>
 * 路径途经的所有单元格都的值都是 0 。<p>
 * 路径中所有相邻的单元格应当在 8 个方向之一 上连通（即，相邻两单元之间彼此不同且共享一条边或者一个角）。<p>
 * 畅通路径的长度 是该路径途经的单元格总数。<p>
 * <p>
 * 示例 1：<p>
 * 输入：grid = [[0,1],[1,0]]<p>
 * 输出：2<p>
 * <p>
 * 示例 2：<p>
 * 输入：grid = [[0,0,0],[1,1,0],[1,1,0]]<p>
 * 输出：4<p>
 * <p>
 * 示例 3：<p>
 * 输入：grid = [[1,0,0],[1,1,0],[1,1,0]]<p>
 * 输出：-1<p>
 * <p>
 * 提示：<p>
 * n == grid.length<p>
 * n == grid[i].length<p>
 * 1 <= n <= 100<p>
 * grid[i][j] 为 0 或 1<p>
 * <p>
 * 来源：力扣（LeetCode）<p>
 * 链接：<a href="https://leetcode.cn/problems/shortest-path-in-binary-matrix">1091. 二进制矩阵中的最短路径</a><p>
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。<p>
 */
public class LeetCode1091 {

    @Test
    public void test01() {
//        int[][] grid = {{0, 1}, {1, 0}};
//        int[][] grid = {{0, 0, 0}, {1, 1, 0}, {1, 1, 0}};
        int[][] grid = {{1, 0, 0}, {1, 1, 0}, {1, 1, 0}};
        System.out.println(new Solution().shortestPathBinaryMatrix(grid));
    }
}

class Solution {

    int[][] nums = {{1, 0}, {1, 1}, {0, 1}, {-1, -1}, {-1, 0}, {0, -1}, {1, -1}, {-1, 1}};

    int[][] grid;

    int n;

    int ans = 0;

    public int shortestPathBinaryMatrix(int[][] grid) {
        // 直接返回
        if (grid[0][0] != 0) {
            return -1;
        }
        // 长度
        n = grid.length;
        this.grid = grid;
        // 起点赋值为 1 ，防止再次经过
        this.grid[0][0] = 1;
        Deque<int[]> q = new ArrayDeque<>();
        q.offer(new int[]{0, 0});
        for (int ans = 1; !q.isEmpty(); ans++) {
            for (int k = q.size(); k > 0; k--) {
                var p = q.poll();
                int i = p[0], j = p[1];
                if (i == n - 1 && j == n - 1) {
                    return ans;
                }
                for (int x = i - 1; x <= i + 1; x++) {
                    for (int y = j - 1; y <= j + 1; y++) {
                        if (x >= 0 && x < n && y >= 0 && y < n && grid[x][y] == 0) {
                            grid[x][y] = 1;
                            q.offer(new int[]{x, y});
                        }
                    }
                }
            }
        }
        // 超时
//        dfs(0, 0, 1);
        return ans == 0 ? -1 : ans;
    }

    public void dfs(int x, int y, int min) {
        // 判断是否到达了终点
        if (x == n - 1 && y == n - 1) {
            ans = ans == 0 ? min : Math.min(ans, min);
        } else if (ans != 0 && min >= ans) {
            // 判断是否路径已经过长
            return;
        }
        for (int[] num : nums) {
            // 从 8 个方向中挑选一个走，判断是否满足条件
            if (x + num[0] >= 0 && x + num[0] < n && y + num[1] >= 0 && y + num[1] < n && grid[x + num[0]][y + num[1]] == 0) {
                grid[x + num[0]][y + num[1]] = 1;
                dfs(x + num[0], y + num[1], min + 1);
                // 回溯
                grid[x + num[0]][y + num[1]] = 0;
            }
        }
    }
}
